package com.infolab.aims.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.infolab.aims.common.PaginationHelper;
import com.infolab.aims.common.QueryHelper;
import com.infolab.aims.common.bean.SearchCriteria;
import com.infolab.aims.common.bean.SearchResult;
import com.infolab.aims.domain.Driver;
import com.infolab.aims.domain.Vehicle;
import com.infolab.aims.service.intf.VehicleService;


@Service
@Transactional
public class VehicleServiceImpl implements VehicleService {
	
	Log logger = LogFactory.getLog(getClass());
	@PersistenceContext
	private EntityManager em;
	
	public void createVehicle(Vehicle vehicle)
	{
		
		Vehicle newVehicle = new Vehicle();
		
		
		BeanUtils.copyProperties(vehicle,newVehicle);
		
		em.persist(newVehicle);
		
		vehicle.setVehicleId(newVehicle.getVehicleId());
		
	}

	public void updateVehicle(Vehicle vehicle) {
		
//		if(vehicle.getSection()==null || vehicle.getSection().getSectionId()==null)
//			vehicle.setSection(null);
		
		Vehicle newVehicle = em.find(Vehicle.class, vehicle.getVehicleId());
		
		BeanUtils.copyProperties(vehicle,newVehicle);
		
		em.merge(newVehicle);
	}


	public Vehicle getVehicle(String vehicleId) {
		
		return em.find(Vehicle.class, vehicleId);
	}

	public Vehicle findVehicle(SearchCriteria searchCriteria) {
		
		List<Vehicle> vehicles = findVehicles(searchCriteria);
		if(vehicles!=null && vehicles.size()==1)
			return vehicles.get(0);
		
		return null;
	}

	public SearchResult searchVehicle(
			SearchCriteria searchCriteria) {
		if(searchCriteria.getCurPage()==null)
			searchCriteria.setCurPage(1);
		
		VehiclePaginationHelper helper = new VehiclePaginationHelper();
		
		return helper.getSearchResultFromQueryHelper(em, searchCriteria);
	}
	
	public void deleteVehicle(String vehicleId) {
		
		Query query = em.createQuery("delete Vehicle where vehicleId=:vehicleId");
		
		query.setParameter("vehicleId", vehicleId);
		
		query.executeUpdate();
		
	}
	
	public static class VehiclePaginationHelper extends PaginationHelper<Vehicle> {

		@Override
		public String[] getValidColumnName() {
			return new String[]{"vehicleId","driverNric","driverName"};
		}
		
		@Override
		public String[] getValidSortName() {
			return new String[]{"vehicleId","driverNric","driverName"};
		}

		@Override
		public String getDefaultSortName() {
			return "vehicleId";
		}
		
		@Override
		public QueryHelper getQueryHelper() {
			QueryHelper queryHelper = new QueryHelper();
			queryHelper.select("select vehicle from Vehicle vehicle");
			return queryHelper;
		}
	}

	public List<Vehicle> findVehicles(SearchCriteria searchCriteria) {
		
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Vehicle> cq = cb.createQuery(Vehicle.class);
		Root<Vehicle> root = cq.from(Vehicle.class);
		List<Predicate> criteria = new ArrayList<Predicate>();
		
		if (searchCriteria.getSearchCriteria("vehicleId")!= null) {
			criteria.add(cb.like(cb.upper(root.<String>get("vehicleId")), "%"+StringUtils.upperCase((String)searchCriteria.getSearchCriteria("vehicleId"))+"%"));
		}
		
		cq.select(root);
		if (criteria.size() == 0) {
			} else if (criteria.size() == 1) {
			cq.where(criteria.get(0));
			} else {
			cq.where(cb.and(criteria.toArray(new Predicate[0])));
		}
		
		if(searchCriteria.getSortType()!=null)
		{
			if(searchCriteria.isAscendingSort())
				cq.orderBy(cb.asc(root.get(searchCriteria.getSortName())));
			else
				cq.orderBy(cb.desc(root.get(searchCriteria.getSortName())));	
		}
		
		Query query = em.createQuery(cq);
		
		if(searchCriteria.getMaxRow()!=null)
			query.setMaxResults(searchCriteria.getMaxRow());
		
		return query.getResultList();
	}
	
	public List<Driver> findDrivers(SearchCriteria searchCriteria) {
		
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Driver> cq = cb.createQuery(Driver.class);
		Root<Driver> root = cq.from(Driver.class);
		List<Predicate> criteria = new ArrayList<Predicate>();
		
		if (searchCriteria.getSearchCriteria("vehicleId")!= null) {
			criteria.add(cb.like(cb.upper(root.<String>get("vehicleId")), "%"+StringUtils.upperCase((String)searchCriteria.getSearchCriteria("vehicleId"))+"%"));
		}
		
		cq.select(root);
		if (criteria.size() == 0) {
			} else if (criteria.size() == 1) {
			cq.where(criteria.get(0));
			} else {
			cq.where(cb.and(criteria.toArray(new Predicate[0])));
		}
		
		if(searchCriteria.getSortType()!=null)
		{
			if(searchCriteria.isAscendingSort())
				cq.orderBy(cb.asc(root.get(searchCriteria.getSortName())));
			else
				cq.orderBy(cb.desc(root.get(searchCriteria.getSortName())));	
		}
		
		Query query = em.createQuery(cq);
		
		if(searchCriteria.getMaxRow()!=null)
			query.setMaxResults(searchCriteria.getMaxRow());
		
		return query.getResultList();
	}
}
